2024-06-09
最后编辑于:2024-06-12
当你用手动使用数组管理一块连续内存时,需要对外提供访问接口,其数据类型还是用户自定义的。
比如说这样一个4KB的内存空间,这里通常用u8
,即以字节为单位
const CHUNCK_SIZE: usize = 0x4000;
struct Chunck {
data: [u8; CHUNCK_SIZE],
}
为了提供对任意位置的访问,需要拿到指定偏移处的指针
impl Chunck {
fn addr_of_offset(&self, offset: usize) -> usize {
&self.data[offset] as *const _ as usize
}
}
很直观,无需多言
然后提供任意内存结构的读取,将拿到的指针转换为对应类型的指针
impl Chunck {
pub fn get_ref<T>(&self, offset: usize) -> &T {
let type_size = core::mem::size_of::<T>();
assert!(offset + type_size <= CHUCK_SIZE);
let addr = self.addr_of_offset(offset);
unsafe { &*(addr as *const T) }
}
pub fn get_mut<T>(&mut self, offset: usize) -> &mut T {
let type_size = core::mem::size_of::<T>();
assert!(offset + type_size <= CHUCK_SIZE);
let addr = self.addr_of_offset(offset);
unsafe { &mut *(addr as *mut T) }
}
}
这里注意解引用裸指针是unsafe
的
进一步封装访问接口
pub fn read<T, V>(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V {
f(self.get_ref(offset))
}
pub fn modify<T, V>(&mut self, offset: usize, f: impl FnOnce(&mut T) -> V) -> V {
f(self.get_mut(offset))
}
用例:
pub struct SuperBlock {
magic: usize,
pub inodes_start: usize,
}
fn main() {
let chunck = Chunck::new();
let value = chunck.read(12, |block: &SuperBlock| {
block.inodes_start
});
println!("inodes start at {:#08x}", value);
}